import { ApiMsgEnum, EntityTypeEnum, IClientInput, InputTypeEnum, IState, toFixed } from "../Common";
import { IMsgClientSync } from "../Common/Msg";
import { Connection } from "../Core/Connection";
import { Player } from "./Player";
import { PlayerManager } from "./PlayerManager";
import { RoomManager } from "./RoomManager";

export class Room {
    rid: number;
    masterId: number;

    lastTime: number
    lastFrameId: number = 0;
    penddingInputs: IClientInput[] = []
    lastPlayersFrameId: Map<number, number> = new Map();
    players: Set<Player> = new Set();
    constructor(rid: number, masterId: number) {
        this.rid = rid;
        this.masterId = masterId;
    }

    join(uid: number) {
        const player = PlayerManager.Instance.idMapPlayers.get(uid);
        if (player) {
            player.rid = this.rid;
            this.players.add(player);
        }
    }

    leave(uid: number) {
        const player = PlayerManager.Instance.idMapPlayers.get(uid);
        if (player) {
            player.rid = undefined;
            this.players.delete(player);
        }
        if (this.masterId === uid) {
            for (const player of this.players) {
                player.connection.sendMsg(ApiMsgEnum.MsgRoomClose, {
                    msg: "房主退出房间，房间自动关闭！"
                });

                player.rid = undefined;
                this.players.delete(player);
            }
        }
    }

    close() {
        this.players.clear();
    }

    start() {
        const state: IState = {
            actors: [...this.players].map((palyer, index) => ({
                id: palyer.id,
                nickname: palyer.nickname,
                position: {
                    x: -150 + index * 300,
                    y: -150 + index * 300,
                },
                direction: {
                    x: 1,
                    y: 0,
                },
                type: EntityTypeEnum.Actor1,
                weaponTpye: EntityTypeEnum.Weapon1,
                bulletType: EntityTypeEnum.Bullet2,
                hp: 100,
            })),
            bullets: [],
            nextBulletId: 0,
            seed: 1
        }
        for (const player of this.players) {
            player.connection.sendMsg(ApiMsgEnum.MsgGameStart, {
                state,
            });
            player.connection.listenMsg(ApiMsgEnum.MsgClientSync, this.getClientMsg, this);
        }

        const timerFrame = setInterval(() => {
            this.sendSeverMsg()
        }, 33)

        const timerPast = setInterval(() => {
            this.timePast()
        }, 16)
    }

    sync() {
        for (const player of this.players) {
            player.connection.sendMsg(ApiMsgEnum.MsgRoomInfo, {
                room: RoomManager.Instance.getRoomView(this),
            });
        }
    }

    getClientMsg(connection: Connection, { frameId, input }: IMsgClientSync) {
        this.penddingInputs.push(input)
        this.lastPlayersFrameId.set(connection.playerId, frameId)
    }

    sendSeverMsg() {
        const inputs = [...this.penddingInputs]
        this.penddingInputs = [];
        for (const player of this.players) {
            const lastFrameId = this.lastPlayersFrameId.get(player.id) ?? 0;
            player.connection.sendMsg(ApiMsgEnum.MsgServerSync, {
                lastFrameId,
                inputs
            });
        }
    }
    timePast() {
        const now = process.uptime();
        const dt = now - (this.lastTime ?? now);
        this.penddingInputs.push({
            type: InputTypeEnum.TimePast,
            dt: toFixed(dt)
        })

        this.lastTime = now;
    }
}
